package game;


import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.KeyListener;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.StateBasedGame;

import vision.Vision;
import controllers.PlayerController;

public class VotingMenu extends TwistyBasicGameState implements KeyListener {

	/**
	 * Class constructor.
	 * @param vision
	 */
	public VotingMenu(Vision vision) {
		super(vision);
	}

	//The booleans that indicate what state will be next
	private boolean goToPaintball = false;
	private boolean goToChasegame = false;
	private boolean goToBallpool = false;
	private boolean goToCredits = false;
	private boolean goToCalibration = false;
	
	//Whether the timer needs to be reset
	private boolean setTime = true;
	//The start time of the timer
	private long startTime;
	//The end time of the timer
	private long endTime;
	//The amount of time the timer needs to run
	private long timerTime = Constants.voteTime;
	
	//The votes that are made for a game
	private HashMap<Integer, Integer> voteMap = new HashMap<Integer, Integer>();
	//The players that have voted
	private ArrayList<Player> votedPlayers = new ArrayList<Player>();
	
	//Credits image
	Image credits;
	
	@Override
	public void init(GameContainer container, StateBasedGame game) throws SlickException {
		credits = new Image("res/twistycredits.png");
	}

	@Override
	public void render(GameContainer container, StateBasedGame game, Graphics g)
			throws SlickException {
		super.render(container, game, g);
		g.setColor(Color.white);
		g.drawImage(credits, (Constants.screenWidth - credits.getWidth()), (Constants.screenHeight - credits.getHeight()));
		g.setBackground(Color.black);
		g.drawString("Welkom bij de twisty game!", 20, 50);
		g.drawString("Vote game:", 20, 100);
		g.drawString("1. Paintball\n2. Chasegame\n3. Ballpool\n4. Credits", 20, 120);
		g.drawString(gameVotesToString(), 150, 120);
		try{
			g.drawString("Connected players: " + PlayerController.getPlayers().size(), 180, 220);
		}catch(Exception e){
			
		}
		g.drawString("Time to vote:" + (int)(((startTime - endTime)*-1)/100) + "s", 180, 240);
	}

	@Override
	public void update(GameContainer container, StateBasedGame game, int delta)
			throws SlickException {
		super.update(container, game, delta);
		if(goToPaintball){
			goToPaintball = false;
			goToGame(1, game);
		}else if(goToChasegame){
			goToChasegame = false;
			goToGame(2, game);
		}else if(goToBallpool){
			goToBallpool = false;
			goToGame(3, game);
		}else if(goToCredits){
			goToCredits = false;
			goToGame(4, game);
		}else if(goToCalibration){
			goToCalibration = false;
			goToGame(5, game);
		}
		try{
			if(PlayerController.getPlayers().size() > 0){
				for(Player p : PlayerController.getPlayers()){
					if(p.getVote() != -1){
						this.voteOnGame(p.getVote(), p);
						p.setVote(-1);
					}
				}
			}
		}catch(Exception e){
			
		}
		handleVotingTimer();
	}
	
	/**
	 * Concatenate the casted votes to a string.
	 * @return A concatenated string of casted votes.
	 */
	public String gameVotesToString(){
		String result = "";
		for(int i = 1; i <= Constants.totalVotableGames ; i++){
			if(voteMap.containsKey(i)){
				result += voteMap.get(i);
				
			}else{
				result += "0";
			}
			result += "\n";
		}
		return result;
	}
	
	/**
	 * Handles the timer for voting
	 */
	public void handleVotingTimer(){
		if(setTime){
			startTime = System.currentTimeMillis();
			endTime = (startTime + timerTime);
			setTime = false;
		}
		if(startTime >= endTime){
			try{
				if(PlayerController.getPlayers().size() > 0 && voteMap.values().size() > 0 && votedPlayers.size() >= (PlayerController.getPlayers().size()/2)){
					int maxValue = Collections.max(voteMap.values());
					for(Integer key : voteMap.keySet()){
						if(voteMap.get(key) == maxValue){
							setAccessToGame(key);
							break;
						}
					}
				}else{
					setTime = true;
				}
			}catch(Exception e){
				
			}
		}
		startTime++;
	}
	
	/**
	 * Sets access to a game
	 * @param game - 
	 */
	public void setAccessToGame(int game){
		switch(game){
		case 1:
			goToPaintball = true;
			break;
		case 2:
			goToChasegame = true;
			break;
		case 3:
			goToBallpool = true;
			break;
		case 4:
			goToCredits = true;
			break;
		}
	}
	
	/**
	 * Handles the statechange
	 * @param gameState 	The state to go to
	 * @param game 			The game container that handles the state transition
	 */
	public void goToGame(int gameState, StateBasedGame game){
		setTime = true;
		voteMap.clear();
		votedPlayers.clear();
		((MainGame)game).enterState(gameState);
	}
	
	/**
	 * Assign a casted vote for a given player.
	 * @param game	Vote ID @see Constants
	 * @param p 	The associated player
	 */
	public void voteOnGame(int game, Player p){
		if(!votedPlayers.contains(p)){
			if(voteMap.containsKey(game)){
				voteMap.put(game, voteMap.get(game)+1);
			}else{
				voteMap.put(game, 1);
			}
			votedPlayers.add(p);
		}
	}
	
	@Override
	public int getID() {
		return Constants.votingMenu;
	}

	@Override
	public void keyPressed(int key, char c) {
		if(key == Input.KEY_1){
			this.voteOnGame(1, new Player(new Socket()));
		}
		if(key == Input.KEY_5){
			goToCalibration = true;
		}
		if(key == Input.KEY_Q){
			System.exit(0);
		}
	}
}
